#include "user.h"
//#define TASK_DBG DBG_INFO
#define TASK_DBG(X, Y...)
static Task_InfoStruct TaskList[TASK_ID_MAX];

static void Task_TimerCB(PV_Union Param)
{
	if (Param.u32 >= TASK_ID_MAX)
		return ;
	TaskList[Param.u32].IsTimerWakeup = 1;
}

void Task_Init(void)
{

}

void Task_Register(uint8_t TaskID, MyTaskFun_t Fun, Signal_InfoStruct *SignalBuf, uint8_t SignalBufLen)
{
	if (TaskID >= TASK_ID_MAX)
		return ;
	if (TaskList[TaskID].Fun)
		return ;
	TaskList[TaskID].Fun = Fun;
	TaskList[TaskID].TaskState = TASK_STATE_WORK;
	TaskList[TaskID].WakeupSignal = SIGNAL_NONE;
	TaskList[TaskID].IsTimerWakeup = 0;
	LoopBuffer_Init(&TaskList[TaskID].SignalQueue, SignalBuf, SignalBufLen, sizeof(Signal_InfoStruct));
	Timer_Register(&TaskList[TaskID].Timer, Task_TimerCB, (void *)TaskID);
}

void Task_Del(uint8_t TaskID)
{
	if (TaskID >= TASK_ID_MAX)
		return ;
	memset(&TaskList[TaskID], 0, sizeof(Task_InfoStruct));
	Timer_Switch(&TaskList[TaskID].Timer, 0);
}

void Task_ResetSignalQueue(uint8_t TaskID)
{
	TaskList[TaskID].SignalQueue.Len = 0;
}

void Task_Wait(uint8_t TaskID, uint16_t Signal, uint32_t To)
{
	if (TaskID >= TASK_ID_MAX)
		return ;
	TASK_DBG("%x, %d %d", Signal, TaskID, To);
	if ((Signal != SIGNAL_NONE) || To)
	{
		TaskList[TaskID].TaskState = TASK_STATE_SLEEP;
	}

	if (To)
	{
		Timer_Start(&TaskList[TaskID].Timer, 0, To, 0);
	}
	if (Signal != SIGNAL_NONE)
	{
		TaskList[TaskID].WakeupSignal = Signal;
	}
}

void Task_SendOnlySignal(uint8_t FromTaskID, uint8_t ToTaskID, uint16_t Signal)
{
	Signal_InfoStruct S;
	int i;

	if (FromTaskID >= TASK_ID_MAX)
		return ;
	S.Param.u32 = 0;
	S.Signal = Signal;
	S.FromTaskID = FromTaskID;
	if (ToTaskID >= TASK_ID_MAX)
	{
		for(i = 0;i < TASK_ID_MAX; i++)
		{
			if (FromTaskID == i)
				continue;
			if (TaskList[i].Fun && (TaskList[i].WakeupSignal == S.Signal))
			{
				S.ToTaskID = i;
				TASK_DBG("%x %d %d", S.Signal, S.FromTaskID, S.ToTaskID);
				LoopBuffer_Write(&TaskList[i].SignalQueue, &S, 1);
			}
		}
		return ;
	}
	S.ToTaskID = ToTaskID;
	TASK_DBG("%x %d %d", S.Signal, S.FromTaskID, S.ToTaskID);
	LoopBuffer_Write(&TaskList[ToTaskID].SignalQueue, &S, 1);
}

void Task_SendSignal(uint8_t FromTaskID, uint8_t ToTaskID, Signal_InfoStruct *Signal)
{
	int i;

	if (FromTaskID >= TASK_ID_MAX)
		return ;
	Signal->FromTaskID = FromTaskID;
	Signal->ToTaskID = ToTaskID;
	if (ToTaskID >= TASK_ID_MAX)
	{
		for(i = 0;i < TASK_ID_MAX; i++)
		{
			if (TaskList[i].WakeupSignal == Signal->Signal)
			{

				TASK_DBG("%x %d %d", Signal->Signal, Signal->FromTaskID, Signal->ToTaskID);
				LoopBuffer_Write(&TaskList[i].SignalQueue, Signal, 1);
			}
		}
		return ;
	}

	TASK_DBG("%x %d %d", Signal->Signal, Signal->FromTaskID, Signal->ToTaskID);
	LoopBuffer_Write(&TaskList[ToTaskID].SignalQueue, Signal, 1);
}

void Task_Wakeup(uint8_t TaskID, Signal_InfoStruct *Signal)
{
	TaskList[TaskID].Timer.Work = 0;
	TaskList[TaskID].IsTimerWakeup = 0;
	TaskList[TaskID].WakeupSignal = SIGNAL_NONE;
	TaskList[TaskID].TaskState = TASK_STATE_WORK;
	TaskList[TaskID].Fun(Signal);
}

void Task_LowPowerRun(void)
{
	;
}

void Task_Run(void)
{
	uint32_t i, SignalCnt, SignalNum;
	Signal_InfoStruct Signal;
	i = 0;
	while (i < TASK_ID_MAX)
	{
		if (!TaskList[i].Fun)
		{
			i++;
			continue;
		}
		SignalNum = TaskList[i].SignalQueue.Len;
		if (!SignalNum && !TaskList[i].IsTimerWakeup)
		{
			if (TaskList[i].TaskState == TASK_STATE_WORK)
			{
				TaskList[i].Fun(NULL);
			}
			i++;
			continue;
		}
		if ( SignalNum )
		{
			for(SignalCnt = 0; SignalCnt < SignalNum; SignalCnt++)
			{
				if (LoopBuffer_Read(&TaskList[i].SignalQueue, &Signal, 1) == 1)
				{
					switch (TaskList[i].WakeupSignal)
					{
					case SIGNAL_NONE:
						TASK_DBG("abort %x %d", Signal.Signal, Signal.FromTaskID);
						break;
					case SIGNAL_ANY:
						Task_Wakeup(i, &Signal);
						break;
					default:
						if (Signal.Signal == TaskList[i].WakeupSignal)
						{
							Task_Wakeup(i, &Signal);
						}
						break;
					}
				}
				else
				{
					TaskList[i].IsTimerWakeup = 0;
					break;
				}
			}
		}
		if (TaskList[i].IsTimerWakeup)
		{
			Signal.Signal = SIGNAL_TASK_TIMEOUT;
			Task_Wakeup(i, &Signal);
		}
		i++;
	}
	for (i = 0; i < TASK_ID_MAX; i++)
	{
		if (TaskList[i].TaskState == TASK_STATE_WORK)
		{
			return;
		}
	}
	Task_LowPowerRun();
}
